package com.apes.fn.server.servicePlan.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.repository.RetailOrderItemRepository;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.fn.server.workOrder.model.MaintenanceOrder;
import com.apes.fn.server.workOrder.repository.MaintenanceOrderRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.oap.RopRequestContext;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.function.Function;

/**
 * @program:
 * @description: 服务方案中间层
 * @author: lws
 * @create: 2023/4/4 11:27
 **/
@Service("servicePlanToInvoke")
public class ServicePlanToInvoke  extends AbstractPlan{

    @Autowired
    private ServicePlanceService servicePlanceService;

    @Autowired
    UserRepository userRepository;

    @Autowired
    private ServicePlanRepository servicePlanRepository;

    @Autowired
    private ServicePlanItemRepository servicePlanItemRepository;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private RetailOrderItemRepository retailOrderItemRepository;
    @Autowired
    private MaintenanceOrderRepository maintenanceOrderRepository;
    /**
     * 方案拆分页面接口调用，入参跟返参修改
     * @param request
     * @return
     */
    public Object servicePlanProcess(SimpleRequest request){
        JSONObject param = request.getJO();
        String method = param.getString("methodId");
        JSONObject data = param.getJSONObject("data");
        return selectProcess(method,data);
    }

    /**
     * 方案拆分页面查询接口
     * @param request
     * @return
     */
    public Object findOneForErp(SimpleRequest request){
        return selectProcess("fn.service.findOneForErp",request.getJO());
    }

    private Object selectProcess(String method, JSONObject data){
        switch(method){
            case "fn.service.checkShowPriceUnitTips": return invokeProcess(method,data,this::checkShowPriceUnitTipsByParam,this::defaultResult);
            case "fn.service.findOneByDept":
            case "fn.service.findOneForErp": return invokeProcess(method,data,this::defaultParam,this::modelProcessByResult);  // 入参：默认；返参：实体修改；
            case "fn.service.getTerminationConfirm": return invokeProcess(method,data,this::modelProcessByParam,this::defaultResult);  // 入参：实体修改；返参：默认；
            default: return invokeProcess(method,data,this::modelProcessByParam,this::modelProcessByResult); // 默认情况：接收实体，返回实体
        }
    }

    private Object invokeProcess(String method, JSONObject data, Function<JSONObject,Map> paramChange, Function<Object,Object> resultChange){
        // 修改入参
        Map param = paramChange.apply(data);
        Object invokeResult = invoke(method, param);
        // 修改返回数据 工时明细：workItems 配件明细：fittingsItems
        return resultChange.apply(invokeResult);
    }

    /**
     * 处理实体类数据入参
     * @param data
     * @return
     */
    private Map modelProcessByParam(JSONObject data){
        data.put("servicePlanItems",getServicePlanItems(data));
        return data;
    }

    /**
     * 处理实体类的返回数据
     * @param invokeResult
     * @return
     */
    public Map modelProcessByResult(Object invokeResult){
        Map result = MapUtil.mapped(invokeResult);
        ServicePlan servicePlan = (ServicePlan) invokeResult;
        if (servicePlan==null)return result;
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems();
        assert result != null;
        splitPlanItems(result, servicePlanItems);
        return result;
    }

    /**
     * 切分明细为工时配件
     * @param result
     * @param servicePlanItems
     */
    public void splitPlanItems(Map result, List<ServicePlanItem> servicePlanItems) {
        Vector<Object> workItemsVector = new Vector<>();
        Vector<Object> fittingsItemsVector = new Vector<>();
        servicePlanItems.stream().forEach(servicePlanItem -> {
            Object mapped = MapUtil.mapped(servicePlanItem);
            String id = servicePlanItem.getProduct().getProductGroup().getId();
            if ("20".equals(id)){
                workItemsVector.add(mapped);
            }else{
                fittingsItemsVector.add(mapped);
            }
        });
        result.put("workItems",workItemsVector);
        result.put("fittingsItems",fittingsItemsVector);
        result.put("servicePlanItemSize",workItemsVector.size()+fittingsItemsVector.size());

        result.remove("servicePlanItems");
    }

    /**
     * 将原本的数据返回
     * @param data
     * @return
     */
    private Map defaultParam(JSONObject data){
        return data;
    }

    /**
     * 将原本的数据返回
     * @param invokeResult
     * @return
     */
    private Object defaultResult(Object invokeResult){
        return invokeResult;
    }

    /**
     * fn.service.checkShowPriceUnitTips 接口入参处理
     * @param data
     * @return
     */
    private Map checkShowPriceUnitTipsByParam(JSONObject data){
        data.put("item",getServicePlanItems(data));
        return data;
    }

    /**
     * 通过工时明细与配件明细获取到服务明细
     * @param data
     * @return
     */
    private JSONArray getServicePlanItems(JSONObject data){
        JSONArray servicePlanItems = new JSONArray();

        JSONArray workItems = data.getJSONArray("workItems");
        JSONArray fittingsItems = data.getJSONArray("fittingsItems");
        if (workItems!=null)servicePlanItems.addAll(workItems);
        if (fittingsItems!=null)servicePlanItems.addAll(fittingsItems);
        return servicePlanItems;
    }

    public Object checkShowPriceUnitTipsFormat(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray servicePlanItems = getServicePlanItems(jo);
        if (servicePlanItems.isEmpty())return jo;
        jo.put("item",servicePlanItems);
        return jo;
    }

    public Object getTerminationConfirmFormat(SimpleRequest request){
        JSONObject jo = request.getJO().getJSONObject("model");
        return MapUtil.mapper("model",servicePlanFormat(jo));
    }

    private Object servicePlanJsonFormat(SimpleRequest request){
        JSONObject jo = request.getJO();
        if(!jo.containsKey("formId") || !"crm.servicePlan".equals(jo.getString("formId"))) return request.getData();
        return servicePlanFormat(jo);
    }

    public Object findOneFormat(SimpleRequest request){
        if (request.getData() instanceof ServicePlan) return servicePlanFormatToWebData(request);
        return null;
    }

    private Object servicePlanFormat(JSONObject jo){
        if(!jo.containsKey("formId") || !"crm.servicePlan".equals(jo.getString("formId"))) return jo;
        JSONArray servicePlanItems = getServicePlanItems(jo);
        if (servicePlanItems.isEmpty())return jo;
//        checkItemsEq(jo,servicePlanItems);
        jo.put("servicePlanItems",servicePlanItems);
        return jo;
    }

    private Object servicePlanFormatToWebData(SimpleRequest request){
        ServicePlan servicePlan =request.getO(ServicePlan.class);
        if (servicePlan.getServicePlanItems().isEmpty())return null;
        RopRequestContext ropRequestContext = request.getRopRequestContext();
        String method = ropRequestContext.getMethod();
        PartyRole person = request.getPerson();
        switch (method){
            case "fn.service.update":
                servicePlanceService.addServicePlanLogger(servicePlan,"修改","",personFindUser(person));
                break;
            case "fn.service.create":
            case "fn.service.localCreate":
                servicePlanceService.addServicePlanLogger(servicePlan,"新增","",personFindUser(person));
                break;
            case "fn.service.confirm":
                servicePlanceService.addServicePlanLogger(servicePlan,"确认","",personFindUser(person));
                break;
            case "fn.service.submission":
                servicePlanceService.addServicePlanLogger(servicePlan,"提交","",personFindUser(person));
                break;
            case "fn.service.termination":
                servicePlanceService.addServicePlanLogger(servicePlan,"终止","",personFindUser(person));
                break;
            case "fn.service.goBack":
                servicePlanceService.addServicePlanLogger(servicePlan,"退回","",personFindUser(person));
                break;
            case "fn.service.launchPriceAudit":
                servicePlanceService.addServicePlanLogger(servicePlan,"发起价格审批流程","",personFindUser(person));
                break;
                default:
                    break;

        }
        Map map = modelProcessByResult(servicePlan);
        return map;
    }

    private User personFindUser(PartyRole person) {
        return person==null? null:userRepository.findAll(JpaDsl.toCriteriaByEq("person.id",person.getId())).stream().findFirst().orElse(null);
    }

    public void checkItemsEq(ServicePlan servicePlan,JSONArray workItems,JSONArray fittingsItems){
        int size = workItems.size() + fittingsItems.size();
        cheItemEq(size, servicePlan.getId());
    }
    public void checkItemsEq(JSONObject jo,JSONArray workItems,JSONArray fittingsItems){
        String id = jo.getString("id");
        int size = workItems.size() + fittingsItems.size();
        cheItemEq(size, id);
    }
    public void checkItemsEq(JSONObject jo,JSONArray newItems){
        String id = jo.getString("id");
        int size = newItems.size();
        cheItemEq(size, id);
    }

    private void cheItemEq(int size, String id) {
        if (id==null)return;
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan.getConfirmDate()==null)return;
        if (servicePlan.getServicePlanItems().size()!=size) throw new RuntimeException("数据异常,请刷新重试");
    }
    private Map forPlanItemsReportData(SimpleRequest request){
        Map map = request.getMap();
        if (map.isEmpty())return map;
        Vector workItems = (Vector) map.get("workItems");
        Vector fittingsItems = (Vector) map.get("fittingsItems");
        intoItemsDetail(workItems,map);
        intoItemsDetail(fittingsItems,map);
        return map;
    }

    private void intoItemsDetail(Vector productItems,Map plan) {
        productItems.forEach(o -> {
            Map productMap = (Map) o;
            String id = (String) productMap.get("id");
            Product product = productRepository.findOne((String) ((Map) productMap.get("product")).get("id"));
            productMap.put("brand", product.getBrand().getName());

            RetailOrderItem retailOrderItem = retailOrderItemRepository.findByOriginnumber(id);
            double qtyReturned = retailOrderItem==null?0:retailOrderItem.getQtyReturned();
            double priceUnit = retailOrderItem==null?0:retailOrderItem.getPriceUnit()*retailOrderItem.getQtyReturned();
            productMap.put("qtyReturned", qtyReturned);
            productMap.put("returnPriceTotal", priceUnit);
            Object relevanceWorkOrder = productMap.get("relevanceWorkOrder");
            String relevanceWorkOrderPlan = "否";
            if (relevanceWorkOrder!=null){
                MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findOne((String) relevanceWorkOrder);
                if (maintenanceOrder!=null){
                    relevanceWorkOrderPlan = maintenanceOrder.getServicePlanId();
                    if (maintenanceOrder.getServicePlanId().equals((String) plan.get("id"))){
                        relevanceWorkOrderPlan="否";
                    }
                }
            }
            productMap.put("crossWork", relevanceWorkOrderPlan);

            MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findByServicePlanItemAndBusinessType(id, "common");
            if (maintenanceOrder==null)maintenanceOrder = maintenanceOrderRepository.findByServicePlanItemAndBusinessType(id, "inner");
            if (maintenanceOrder==null)maintenanceOrder = maintenanceOrderRepository.findByServicePlanItemAndNotTermination(id);
            if (maintenanceOrder!=null){
                String worker1Show = maintenanceOrder.getWorker1Show()==null?"":maintenanceOrder.getWorker1Show()+"|";
                String worker2Show = maintenanceOrder.getWorker2Show()==null?"":maintenanceOrder.getWorker2Show()+"|";
                String worker3Show = maintenanceOrder.getWorker3Show()==null?"":maintenanceOrder.getWorker3Show()+"|";
                String worker4Show = maintenanceOrder.getWorker4Show()==null?"":maintenanceOrder.getWorker4Show();
                productMap.put("workers", worker1Show+worker2Show+worker3Show+worker4Show);

                productMap.put("maintenanceOrderState", maintenanceOrder.getStateName());
                productMap.put("workStateName", maintenanceOrder.getWorkStateName());
                productMap.put("finishDate", maintenanceOrder.getFinishDate()==null?"--":DateUtil.format(maintenanceOrder.getFinishDate(),DateUtil.SHOW_DATETIME_FORMAT));
                productMap.put("toInnerDate", maintenanceOrder.getToInnerDate()==null?"--":DateUtil.format(maintenanceOrder.getToInnerDate(),DateUtil.SHOW_DATETIME_FORMAT));
                productMap.put("innerDept", maintenanceOrder.getInnerDept()==null?"--":maintenanceOrder.getInnerDept().getName());
                productMap.put("toOutDate", maintenanceOrder.getToOutDate()==null?"--":DateUtil.format(maintenanceOrder.getToOutDate(),DateUtil.SHOW_DATETIME_FORMAT));

            }
        });
    }

}
